package com.spa.application.service.admin;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.spa.application.dto.admin.IndexDTO;
import com.spa.application.dto.admin.IndexStatisticDTO;
import com.spa.application.query.admin.IndexStatisticQuery;
import com.spa.domain.entity.OrderInfo;
import com.spa.domain.entity.UserInfo;
import com.spa.domain.service.MassageService;
import com.spa.domain.service.OrderService;
import com.spa.domain.service.ShopService;
import com.spa.domain.service.UserInfoService;
import com.spa.infrastructure.enums.dict.order.OrderStatusEnum;
import com.spa.infrastructure.repository.condition.OrderInfoCondition;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AdminIndexService {

    @Autowired
    private ShopService shopService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private MassageService massageService;

    @Autowired
    private OrderService orderService;

    public IndexDTO index() {
        IndexDTO indexDTO = new IndexDTO();
        long shopNums = shopService.countAllShop();
        long userNums = userInfoService.countAllUser();
        long serviceNums = massageService.countAllMassageService();
        long orderNums = orderService.countByCondition(new OrderInfoCondition());
        Date date = new Date();
        String beginDate = com.spa.infrastructure.util.DateUtil.date2Str(com.spa.infrastructure.util.DateUtil.getStartTimeOfCurrentDay(date));
        String endDate = com.spa.infrastructure.util.DateUtil.date2Str(com.spa.infrastructure.util.DateUtil.getEndTimeOfCurrentDay(date));
        OrderInfoCondition countCondition = new OrderInfoCondition();
        countCondition.setBeginDate(beginDate);
        countCondition.setEndDate(endDate);
        long todayOrderNums = orderService.countByCondition(countCondition);
        List<Integer> statusList = Lists.newArrayList(OrderStatusEnum.$20.getCode(), OrderStatusEnum.$30.getCode(), OrderStatusEnum.$40.getCode());
        OrderInfoCondition condition = new OrderInfoCondition();
        condition.setStatusList(statusList);
        condition.setBeginDate(beginDate);
        condition.setEndDate(endDate);
        List<OrderInfo> orderInfos = orderService.orderList(condition);
        int todayPrice = 0;
        int extTotalPrice = 0;
        if (CollUtil.isNotEmpty(orderInfos)) {
            todayPrice = orderInfos.stream().mapToInt(info -> ObjectUtil.defaultIfNull(info.getOrderPrice(), 0)).sum();
            extTotalPrice = orderInfos.stream().filter(orderInfo -> orderInfo.getStatus()==40 || orderInfo.getStatus()==30).mapToInt(info -> ObjectUtil.defaultIfNull(info.getExtTotalPrice(), 0)).sum();
        }
        long newUserNums = userInfoService.countNewUserPerDay();
        List<UserInfo> userInfoList = userInfoService.getNewUserListPerDay();
        List<Long> userIds = userInfoList.stream().map(UserInfo::getId).toList();
        OrderInfoCondition orderInfoCondition = new OrderInfoCondition();
        orderInfoCondition.setStatusList(statusList);
        orderInfoCondition.setUserIds(userIds);
        List<OrderInfo> orderInfos0 = orderService.orderList(orderInfoCondition);
        //下单的新用户数
        long orders = orderInfos0.stream().mapToLong(OrderInfo::getUserId).distinct().count();
        indexDTO.setTotalShop(shopNums);
        indexDTO.setTotalUser(userNums);
        indexDTO.setTotalService(serviceNums);
        indexDTO.setTotalOrder(orderNums);
        indexDTO.setTodayOrder(todayOrderNums);
        indexDTO.setTodayPrice(todayPrice + extTotalPrice);
        if (newUserNums != 0) {
            indexDTO.setTodayNewUser(newUserNums);
            BigDecimal bigDecimal = BigDecimal.valueOf(orders).divide(BigDecimal.valueOf(newUserNums), 2, RoundingMode.DOWN);
            indexDTO.setUserConversionRate(bigDecimal);
        }
        indexDTO.setIndexStatistic(indexStatistic0(0));
        return indexDTO;
    }

    public IndexStatisticDTO indexStatistic(IndexStatisticQuery query) {
        return indexStatistic0(query.getIndex());
    }

    private IndexStatisticDTO indexStatistic0(int index) {
        IndexStatisticDTO indexStatisticDTO = IndexStatisticDTO.builder().build();
        Pair<String, String> pair = getBeginAndEndTime(index);
        List<UserInfo> userInfos = userInfoService.getUserListByTime(pair.getLeft(), pair.getRight());
        userInfos.forEach(userInfo -> userInfo.setDate(DateUtil.format(userInfo.getRegTime(), "yyyy-MM-dd")));
        Map<String, List<UserInfo>> userMap = userInfos.stream().collect(Collectors.groupingBy(UserInfo::getDate));

        OrderInfoCondition orderInfoCondition = new OrderInfoCondition();
        orderInfoCondition.setBeginDate(pair.getLeft());
        orderInfoCondition.setEndDate(pair.getRight());
        List<OrderInfo>  orderInfos = orderService.orderList(orderInfoCondition);
        List<OrderInfo> inServiceOrders = orderInfos.stream()
                .filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$30.getCode()) || Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$40.getCode()))
                .toList();
        inServiceOrders.forEach(orderInfo -> orderInfo.setDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd")));
        Map<String, List<OrderInfo>> map = inServiceOrders.stream().collect(Collectors.groupingBy(OrderInfo::getDate));
        List<IndexStatisticDTO.Pair> priceList = new ArrayList<>();
        List<IndexStatisticDTO.Pair> newUserList = new ArrayList<>();
        map.forEach(((s, order) -> {
            IndexStatisticDTO.Pair price = IndexStatisticDTO.Pair.builder()
                    .key(s)
                    .value(order.stream().mapToInt(OrderInfo::getOrderPrice).sum())
                    .build();
            priceList.add(price);
        }));
        userMap.forEach(((s, user) -> {
            IndexStatisticDTO.Pair price = IndexStatisticDTO.Pair.builder()
                    .key(s)
                    .value(user.size())
                    .build();
            newUserList.add(price);
        }));
        priceList.sort(Comparator.comparing(IndexStatisticDTO.Pair::getKey));
        newUserList.sort(Comparator.comparing(IndexStatisticDTO.Pair::getKey));
        indexStatisticDTO.setPriceList(priceList);
        indexStatisticDTO.setNewUserList(newUserList);
        return indexStatisticDTO;
    }

    private Pair<String, String> getBeginAndEndTime(int index) {
        LocalDate now = LocalDate.now();
        LocalDate end = LocalDate.now();
        if (index == 1) {
            now = now.minusMonths(3);
        } else if (index == 2) {
            now = now.minusMonths(6);
        }
        LocalDate firstDay = now.with(TemporalAdjusters.firstDayOfMonth()); // 获取当前月的第一天
        LocalDate lastDay = end.with(TemporalAdjusters.lastDayOfMonth()); // 获取当前月的最后一天
        String beginTime = firstDay + " 00:00:00";
        String endTime = lastDay + " 23:59:59";
        return new ImmutablePair<>(beginTime, endTime);
    }
}
